%{
#include "compile.h"

extern "C" 
{
    int yywrap(void);
	int yyparse();
    void yyerror(const char *str);
//	extern int yylex();
}
extern int yylineno;
extern char* yytext;
extern int yyleng;
extern int yycolumn;
int yylex(void);

//void yyerror(const char *str, YYLTYPE *loc);
void yyerror(const char *str, int line, int col);
void yyerror(const char *str, int startLine, int startCol, int endLine, int endCol);
extern void lex_error_print(void);
extern FILE* yyin;
parse* root = nullptr;
parse* last = nullptr;
vector<string> yacc_error;
parse* syntax_process(const char* file_path);
%}

//关键字
%token ID NUM SSCH MMCH
%token ASSIGNOP
%token EQUAL NEQUAL LESS LE GREATER GE
%token ADD SUB OR
%token MUL DIVISION DIV MOD AND
%token COMMA SEMICOLON DOT DDOT LPAR RPAR LBAR RBAR COLON
%token ARRAY CASE CONST DO DOWNTO ELSE END FOR FUNCTION IF NOT OF PROCEDURE PROGRAM RECORD REPEAT THEN TO TYPE UNTIL VAR WHILE BEGINN
%token BOOLEAN INTEGER REAL CHAR STRING

%start PPROGRAM
%left '+' '-' ADD
%left '*' '/' MUL
%nonassoc LOWER_THAN_ELSE
%nonassoc ELSE

%locations

%%
    PPROGRAM: program_head SEMICOLON program_body DOT {               
            $$ = new parse(0, "PPROGRAM", "");
            $$->children.push_back($1);
            $$->children.push_back($2);
            $$->children.push_back($3);
            $$->children.push_back($4);
            root = $$;
            printf("yes\n");
            last = $$;
            if(yylex()){ //多余的内容
				yyerror("redundant content at the end!", @3.last_line, @3.last_column+1);
            }
			YYACCEPT;
            }
            |program_head error program_body DOT {//没分号      
				$$ = new parse(0, "PPROGRAM", "");
				yyerror("There need a semicolon", @1.last_line, @1.last_column+1);
            }|program_head SEMICOLON program_body error{ //没有结尾的点号
				$$ = new parse(0, "PPROGRAM", "");
				yyerror("There need a dot to end the program", @3.last_line, @3.last_column+1);
			}|error SEMICOLON program_body DOT{ //program_head识别失败
			   	$$ = new parse(0, "PPROGRAM", "");
				yyerror("The program cannot be recognized",@1.first_line, @1.first_column, @1.last_line, @1.last_column);		
			}|program_head SEMICOLON error DOT{ //ERROR program_body识别失败
			   	$$ = new parse(0, "PPROGRAM", "");
				yyerror("The program body has vital error");
			};	
    program_head: PROGRAM ID LPAR identifier_list RPAR {               
                $$ = new parse(0, "program_head", "");
                $$->children.push_back($1);
                $$->children.push_back($2);
                $$->children.push_back($3);
                $$->children.push_back($4);
                $$->children.push_back($5);
                last = $$;
                }|PROGRAM error LPAR identifier_list RPAR {  //主程序名没写
                $$ = new parse(0, "program_head", "");
                yyerror("There need program ID", @1.last_line, @1.last_column+1);
                }|error ID LPAR identifier_list RPAR {//program识别失败
				$$ = new parse(0, "program_head", "");
				yyerror("Cannot find program head",@1.first_line, @1.first_column, @1.last_line, @1.last_column);	
                }|error ID error identifier_list RPAR {//无左括号             
					$$ = new parse(0, "program_head", "");
					yyerror("Missing '(' here", @2.last_line, @2.last_column+1);
                }|error ID LPAR error RPAR {//idlist缺失               
					$$ = new parse(0, "program_head", "");
					yyerror("Need identifier_list", @3.last_line, @3.last_column+1);
				}|error ID LPAR identifier_list error {//没有右括号               
					$$ = new parse(0, "program_head", "");
					yyerror("Missing ')' here", @4.last_line, @4.last_column+1);
                }
                ;
    program_body: const_declarations type_declarations var_declarations subprogram_declarations compound_statement {             
                $$ = new parse(0, "program_body", "");
                $$->children.push_back($1);
                $$->children.push_back($2);
                $$->children.push_back($3);
                $$->children.push_back($4);
                $$->children.push_back($5);
                last = $$;
                }
                ;
    identifier_list: identifier_list COMMA ID {             
                   $$ = new parse(0, "identifier_list", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   last = $$;
                   }|identifier_list error ID {
                    $$ = new parse(0, "identifier_list", "");
                    yyerror("Maybe you should a ','", @1.last_line, @1.last_column+1);
                   }
                   | ID {             
                   $$ = new parse(0, "identifier_list", "");
                   $$->children.push_back($1);
                   last = $$;
                   }
                   ;
    const_declarations: CONST const_declaration SEMICOLON {             
                      $$ = new parse(0, "const_declarations", "");
                      $$->children.push_back($1);
                      $$->children.push_back($2);
                      $$->children.push_back($3);
                      last = $$;
                      }
                      | {             
                      $$ = new parse(0, "const_declarations", "");
                      last = $$;
                      }|CONST error SEMICOLON {//常量定义出现错误             
						$$ = new parse(0, "const_declarations", "");
						yyerror("Const declarations have error", @2.first_line, @2.first_column, @2.last_line, @2.last_column);
					  }|CONST const_declaration error {//无分号             
						$$ = new parse(0, "const_declarations", "");
						yyerror("Maybe you should write a semicolon here", @2.last_line, @2.last_column+1);
					  }
                      ;
    const_declaration: const_declaration SEMICOLON ID EQUAL const_variable {             
                     $$ = new parse(0, "const_declaration", "");
                     $$->children.push_back($1);
                     $$->children.push_back($2);
                     $$->children.push_back($3);
                     $$->children.push_back($4);
                     $$->children.push_back($5);
                     last = $$;
                     }|const_declaration SEMICOLON ID EQUAL error {//常数初始化右值缺失             
						$$ = new parse(0, "const_declaration", "");
						yyerror("This constant definition is equal to what?", @4.first_line, @4.first_column, @4.last_line, @4.last_column);
					 }|const_declaration error ID EQUAL const_variable {//没有分号
						$$ = new parse(0, "const_declaration", "");
						yyerror("Where is the semicolon", @1.first_line, @1.first_column, @1.last_line, @1.last_column+1);
					 }|const_declaration SEMICOLON ID error const_variable {//没有等号
						$$ = new parse(0, "const_declaration", "");
						yyerror("Where is the equal operation", @3.first_line, @3.first_column, @3.last_line, @3.last_column+1);
					}
                     | ID EQUAL const_variable {             
                     $$ = new parse(0, "const_declaration", "");
                     $$->children.push_back($1);
                     $$->children.push_back($2);
                     $$->children.push_back($3);
                     last = $$;
                     }|ID EQUAL error {//常数初始化右值缺失             
						$$ = new parse(0, "const_declaration", "");
						yyerror("This constant definition is equal to what?", @3.first_line, @3.first_column, @3.last_line, @3.last_column);
					 }|ID error const_variable {//缺少等号           
						$$ = new parse(0, "const_declaration", "");
						yyerror("Where is the equal operation", @1.last_line, @1.last_column+1);
					 }
                     ;
    const_variable: ADD ID {             
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  $$->children.push_back($2);
                  last = $$;
                  }
                  | SUB ID {             
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  $$->children.push_back($2);
                  last = $$;
                  }
                  | ID {             
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  last = $$;
                  }
                  | ADD NUM {             
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  $$->children.push_back($2);
                  last = $$;
                  }
                  | SUB NUM {             
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  $$->children.push_back($2);
                  last = $$;
                  }
                  | NUM {             
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  last = $$;
                  }
                  | SSCH {
                  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  last = $$;                      
                  }
				  | MMCH {
				  $$ = new parse(0, "const_variable", "");
                  $$->children.push_back($1);
                  last = $$; 
				  }
                  ;
    type_declarations: TYPE type_declaration SEMICOLON {             
                     $$ = new parse(0, "type_declarations", "");
                     $$->children.push_back($1);
                     $$->children.push_back($2);
                     $$->children.push_back($3);
                     last = $$;
                     }
                     | {             
                     $$ = new parse(0, "type_declarations", "");
                     last = $$;
                     }|TYPE error SEMICOLON {             
						$$ = new parse(0, "type_declarations", "");
						yyerror("There needs type_declarations", @2.first_line, @2.first_column, @2.last_line, @2.last_column);
					 }|TYPE type_declaration error {             
						$$ = new parse(0, "type_declarations", "");
						yyerror("There misses a semicolon", @3.last_line, @3.last_column+1);
					 }
                     ;
    type_declaration: type_declaration SEMICOLON ID EQUAL PTYPE {             
                    $$ = new parse(0, "type_declaration", "");
                    $$->children.push_back($1);
                    $$->children.push_back($2);
                    $$->children.push_back($3);
                    $$->children.push_back($4);
                    $$->children.push_back($5);
                    last = $$;
                    }
                    | ID EQUAL PTYPE {             
                    $$ = new parse(0, "type_declaration", "");
                    $$->children.push_back($1);
                    $$->children.push_back($2);
                    $$->children.push_back($3);
                    last = $$;
                    }|type_declaration error ID EQUAL PTYPE {
						 $$ = new parse(0, "type_declaration", "");
						 yyerror("There misses a semicolon", @2.last_line, @2.last_column+1);
					}|type_declaration SEMICOLON error EQUAL PTYPE {
						 $$ = new parse(0, "type_declaration", "");
						 yyerror("There need ID", @3.first_line, @3.first_column, @3.last_line, @3.last_column);
					}|type_declaration SEMICOLON ID error PTYPE {
						 $$ = new parse(0, "type_declaration", "");
						 yyerror("There misses a equal symbol", @3.last_line, @3.last_column+1);
					}
                    ;
    PTYPE: standard_type {             
         $$ = new parse(0, "PTYPE", "");
         $$->children.push_back($1);
         last = $$;
         }
         | RECORD record_body END {             
         $$ = new parse(0, "PTYPE", "");
         $$->children.push_back($1);
         $$->children.push_back($2);
         $$->children.push_back($3);
         last = $$;
         }
         | ARRAY LBAR periods RBAR OF PTYPE {             
         $$ = new parse(0, "PTYPE", "");
         $$->children.push_back($1);
         $$->children.push_back($2);
         $$->children.push_back($3);
         $$->children.push_back($4);
         $$->children.push_back($5);
         $$->children.push_back($6);
         last = $$;
         }
         ;
    standard_type: INTEGER {             
                 $$ = new parse(0, "standard_type", "");
                 $$->children.push_back($1);
                 last = $$;
                 }
                 | REAL {              
                 $$ = new parse(0, "standard_type", "");
                 $$->children.push_back($1);
                 last = $$;
                 }
                 | BOOLEAN {             
                 $$ = new parse(0, "standard_type", "");
                 $$->children.push_back($1);
                 last = $$;
                 }
                 | CHAR {             
                 $$ = new parse(0, "standard_type", "");
                 $$->children.push_back($1);
                 last = $$;
                 }
				 | STRING {
				 $$ = new parse(0, "standard_type", "");
                 $$->children.push_back($1);
                 last = $$;
				 }
                 ;
    record_body: var_declaration {             
               $$ = new parse(0, "record_body", "");
               $$->children.push_back($1);
               last = $$;
               }
               | {             
               $$ = new parse(0, "record_body", "");
               last = $$;
               }
               ;
    periods: periods COMMA period {             
           $$ = new parse(0, "periods", "");
           $$->children.push_back($1);
           $$->children.push_back($2);
           $$->children.push_back($3);
           last = $$;
           }
           | period {             
           $$ = new parse(0, "periods", "");
           $$->children.push_back($1);
           last = $$;
           }
           ;
    period: const_variable DDOT const_variable {             
          $$ = new parse(0, "period", "");
          $$->children.push_back($1);
          $$->children.push_back($2);
          $$->children.push_back($3);
          last = $$;
          }|const_variable error const_variable{//缺少双点号
		  $$ = new parse(0, "period", "");
		  yyerror("There misses a DDOT", @1.last_line, @1.last_column+1);
          };
          ;
    var_declarations: VAR var_declaration SEMICOLON {             
                    $$ = new parse(0, "var_declarations", "");
                    $$->children.push_back($1);
                    $$->children.push_back($2);
                    $$->children.push_back($3);
                    last = $$;
                    }
                    | {             
                    $$ = new parse(0, "var_declarations", "");
                    last = $$;
                    }|VAR error SEMICOLON {             
                    $$ = new parse(0, "var_declarations", "");
					yyerror("Variable declarations have got error", @2.first_line, @2.first_column, @2.last_line, @2.last_column);
					}|VAR var_declaration error {             
                    $$ = new parse(0, "var_declarations", "");
					yyerror("There misses a semicolon", @2.last_line, @2.last_column+1);
					}
                    ;
    var_declaration: var_declaration SEMICOLON identifier_list COLON PTYPE {             
                   $$ = new parse(0, "var_declaration", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   $$->children.push_back($4);
                   $$->children.push_back($5);
                   last = $$;
                   }
                   | identifier_list COLON PTYPE {             
                   $$ = new parse(0, "var_declaration", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   last = $$;
                   }|var_declaration error identifier_list COLON PTYPE {//没分号        
                   $$ = new parse(0, "var_declaration", "");
				   yyerror("There miss a semicolon", @1.last_line, @1.last_column+1);
                   }|var_declaration SEMICOLON identifier_list error PTYPE {//没冒号             
                   $$ = new parse(0, "var_declaration", "");
				   yyerror("There miss a colon", @3.last_line, @3.last_column+1);
                   }|var_declaration SEMICOLON identifier_list COLON error {//type识别失败             
                   $$ = new parse(0, "var_declaration", "");
				   yyerror("There has error in standard_type declaration", @4.last_line, @4.last_column+1);
                   }
                   ;
    subprogram_declarations: subprogram_declarations subprogram_declaration SEMICOLON {             
                           $$ = new parse(0, "subprogram_declarations", "");
                           $$->children.push_back($1);
                           $$->children.push_back($2);
                           $$->children.push_back($3);
                           last = $$;
                           }
                           | {             
                           $$ = new parse(0, "subprogram_declarations", "");
                           last = $$;
                           }|subprogram_declarations subprogram_declaration error {             
                           $$ = new parse(0, "subprogram_declarations", "");
						   yyerror("There miss a semicolon", @2.last_line, @2.last_column+1);
                           }
                           ;
    subprogram_declaration: subprogram_head SEMICOLON program_body {             
                          $$ = new parse(0, "subprogram_declaration", "");
                          $$->children.push_back($1);
                          $$->children.push_back($2);
                          $$->children.push_back($3);
                          last = $$;
                          }|subprogram_head error program_body {             
                          $$ = new parse(0, "subprogram_declaration", "");
						  yyerror("There miss a semicolon", @2.first_line, @2.first_column, @2.last_line, @2.last_column+1);
                          }
                          ;
    subprogram_head: FUNCTION ID formal_parameter COLON standard_type {             
                   $$ = new parse(0, "subprogram_head", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   $$->children.push_back($4);
                   $$->children.push_back($5);
                   last = $$;
                   }
                   | PROCEDURE ID formal_parameter {             
                   $$ = new parse(0, "subprogram_head", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   last = $$;
                   }|FUNCTION error formal_parameter COLON standard_type{ //函数名缺失
						$$ = new parse(0, "subprogram_head", "");
						yyerror("Do not find the name of function", @1.last_line, @1.last_column+1);
				   }|FUNCTION ID formal_parameter error standard_type{ //冒号缺失
						$$ = new parse(0, "subprogram_head", "");
						yyerror("There miss a colon", @3.last_line, @3.last_column+1);
				   }|FUNCTION ID formal_parameter COLON error{ //缺少基本类型
						$$ = new parse(0, "subprogram_head", "");
						yyerror("There has error in standard_type declaration", @4.last_line, @4.last_column+1);
				   }|FUNCTION ID formal_parameter error{ //缺少基本类型
						$$ = new parse(0, "subprogram_head", "");
						yyerror("There has error in standard_type declaration", @3.last_line, @3.last_column+1);
				   }|FUNCTION error{ //函数头不完整
						$$ = new parse(0, "subprogram_head", "");
						yyerror("The function head is incompleted",@1.first_line, @1.first_column, @1.last_line, @1.last_column);
				   }|PROCEDURE error{ //过程头不完整
						$$ = new parse(0, "subprogram_head", "");
						yyerror("The procedure head is incompleted",@1.first_line, @1.first_column, @1.last_line, @1.last_column);
				   }
                   ;
    formal_parameter: LPAR parameter_lists RPAR {             
                    $$ = new parse(0, "formal_parameter", "");
                    $$->children.push_back($1);
                    $$->children.push_back($2);
                    $$->children.push_back($3);
                    last = $$;
                    }
                    | {             
                    $$ = new parse(0, "formal_parameter", "");
                    last = $$;
                    }|LPAR parameter_lists error {//没右括号       
                    $$ = new parse(0, "formal_parameter", "");
					yyerror("There miss a right bracket", @2.last_line, @2.last_column+1);
                    }|LPAR error {//形参列表不完整      
                    $$ = new parse(0, "formal_parameter", "");
					yyerror("The incomplete formal parameter list is fatal",@1.first_line, @1.first_column, @1.last_line, @1.last_column);
                    }
                    ;
    parameter_lists: parameter_lists SEMICOLON parameter_list {             
                   $$ = new parse(0, "parameter_lists", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   last = $$;
                   }
                   | parameter_list {             
                   $$ = new parse(0, "parameter_lists", "");
                   $$->children.push_back($1);
                   last = $$;
                   }|parameter_lists error parameter_list {//没分号       
                   $$ = new parse(0, "parameter_lists", "");
				   yyerror("There miss a semicolon", @1.last_line, @1.last_column+1);
                   }
                   ;
    parameter_list: var_parameter {             
                  $$ = new parse(0, "parameter_list", "");
                  $$->children.push_back($1);
                  last = $$;
                  }
                  | value_parameter {             
                  $$ = new parse(0, "parameter_list", "");
                  $$->children.push_back($1);
                  last = $$;
                  }
                  ;
    var_parameter: VAR value_parameter {             
                 $$ = new parse(0, "var_parameter", "");
                 $$->children.push_back($1);
                 $$->children.push_back($2);
                 last = $$;
                 }|VAR error{ //不完整的引用参数列表
				 $$ = new parse(0, "var_parameter", "");
				 yyerror("The incomplete refereced parameter list is fatal",@1.first_line, @1.first_column, @1.last_line, @1.last_column);
                 }
                 ;
    value_parameter: identifier_list COLON standard_type {              
                   $$ = new parse(0, "value_parameter", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   last = $$;
                   }|identifier_list error standard_type {//没分号              
                   $$ = new parse(0, "var_parameter", "");
                   yyerror("There miss a colon", @1.first_line, @1.last_column+1);
				   }identifier_list COLON error {//缺少基本类型              
                   $$ = new parse(0, "var_parameter", "");
				   yyerror("There has error in standard_type declaration", @2.last_line, @2.last_column+1);
				   }|identifier_list error {//缺少基本类型              
                   $$ = new parse(0, "var_parameter", "");
				   yyerror("There has error in standard_type declaration", @2.last_line, @2.last_column+1);
				   }
                   ;
    compound_statement: BEGINN statement_list END {             
                      $$ = new parse(0, "compound_statement", "");
                      $$->children.push_back($1);
                      $$->children.push_back($2);
                      $$->children.push_back($3);
                      last = $$;
                      }//|BEGINN statement_list error {//缺少END             
//                      $$ = new parse(0, "compound_statement", "");
//                      yyerror("We do not know where is the end", @2.last_line, @2.last_column+1);
//					  }
//                      ;
    statement_list: statement_list SEMICOLON statement {             
                  $$ = new parse(0, "statement_list", "");
                  $$->children.push_back($1);
                  $$->children.push_back($2);
                  $$->children.push_back($3);
                  last = $$;
                  }
                  | statement {             
                  $$ = new parse(0, "statement_list", "");
                  $$->children.push_back($1);
                  last = $$;
                  }|statement_list error statement {//没有分号           
                  $$ = new parse(0, "statement_list", "");
                  yyerror("There miss a semicolon", @1.last_line, @1.last_column+1);
				  }
                  ;
    statement: variable ASSIGNOP expression {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             $$->children.push_back($3);
             last = $$;
             } 
             | call_procedure_statement {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             last = $$;
             }
             | compound_statement {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             last = $$;
             }
             | IF expression THEN statement else_part {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             $$->children.push_back($3);
             $$->children.push_back($4);
             $$->children.push_back($5);
             last = $$;
             }|IF expression error statement else_part {//缺少then关键字             
             $$ = new parse(0, "statement", "");
			 yyerror("IF......, the operation then cannot be recognized", @2.last_line, @2.last_column+1);
			 }
             | CASE expression OF case_body END {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             $$->children.push_back($3);
             $$->children.push_back($4);
             $$->children.push_back($5);
             last = $$;
             }
             | WHILE expression DO statement {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             $$->children.push_back($3);
             $$->children.push_back($4);
             last = $$;
             }
             | REPEAT statement_list UNTIL expression {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             $$->children.push_back($3);
             $$->children.push_back($4);
             last = $$;
             }
             | FOR ID ASSIGNOP expression updown expression DO statement {             
             $$ = new parse(0, "statement", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             $$->children.push_back($3);
             $$->children.push_back($4);
             $$->children.push_back($5);
             $$->children.push_back($6);
             $$->children.push_back($7);
             $$->children.push_back($8);
             last = $$;
             }|FOR ID error expression updown expression DO statement {//没有赋值号             
             $$ = new parse(0, "statement", "");
			 yyerror("There miss an assign operation", @2.last_line, @2.last_column+1);
			 }
             | {             
             $$ = new parse(0, "statement", "");
             last = $$;
             }
             ;
    variable: ID id_varparts {             
            $$ = new parse(0, "variable", "");
            $$->children.push_back($1);
            $$->children.push_back($2);
            last = $$;
            }
            ;
    id_varparts: id_varparts id_varpart {             
               $$ = new parse(0, "id_varparts", "");
               $$->children.push_back($1);
               $$->children.push_back($2);
               last = $$;
               }
               | {             
               $$ = new parse(0, "id_varparts", "");
               last = $$;
               }
               ;
    id_varpart: LBAR expression_list RBAR {             
              $$ = new parse(0, "id_varpart", "");
              $$->children.push_back($1);
              $$->children.push_back($2);
              $$->children.push_back($3);
              last = $$;
              }//|LBAR expression_list error {//右中括号缺失          
//              $$ = new parse(0, "id_varpart", "");
//			  yyerror("There miss a right square bracket", @2.last_line, @2.last_column+1);
//			  }
              | DOT ID {             
              $$ = new parse(0, "id_varpart", "");
              $$->children.push_back($1);
              $$->children.push_back($2);
              last = $$;
              }//|error ID {             
//              $$ = new parse(0, "id_varpart", "");
//			  yyerror("We need dot here", @1.last_line, @1.last_column);
//			  }
//              ; 
    else_part: ELSE statement {             
             $$ = new parse(0, "else_part", "");
             $$->children.push_back($1);
             $$->children.push_back($2);
             last = $$;
             }//|error statement {             
//             $$ = new parse(0, "else_part", "");
//			 yyerror("There need word 'else'", @1.last_line, @1.last_column);
//			 }
             | %prec LOWER_THAN_ELSE {             
             $$ = new parse(0, "else_part", "");
             last = $$;
             }
             ;
    case_body: branch_list {             
             $$ = new parse(0, "case_body", "");
             $$->children.push_back($1);
             last = $$;
             }
             | {             
             $$ = new parse(0, "case_body", "");
             last = $$;
             }
             ;
    branch_list: branch_list SEMICOLON branch {             
               $$ = new parse(0, "branch_list", "");
               $$->children.push_back($1);
               $$->children.push_back($2);
               $$->children.push_back($3);
               last = $$;
               }|branch_list error branch {             
               $$ = new parse(0, "branch_list", "");
			   yyerror("There miss a semicolon", @1.last_line, @1.last_column+1);
			   }
               | branch {             
               $$ = new parse(0, "branch_list", "");
               $$->children.push_back($1);
               last = $$;
               }
               ;
    branch: const_list COLON statement {             
          $$ = new parse(0, "branch", "");
          $$->children.push_back($1);
          $$->children.push_back($2);
          $$->children.push_back($3);
          last = $$;
          }
          ;
    const_list: const_list COMMA const_variable {             
              $$ = new parse(0, "const_list", "");
              $$->children.push_back($1);
              $$->children.push_back($2);
              $$->children.push_back($3);
              last = $$;
              }
              | const_variable {             
              $$ = new parse(0, "const_list", "");
              $$->children.push_back($1);
              last = $$;
              }
              ;
    updown: TO {             
          $$ = new parse(0, "updown", "");
          $$->children.push_back($1);
          last = $$;
          }
          | DOWNTO {             
          $$ = new parse(0, "updown", "");
          $$->children.push_back($1);
          last = $$;
          }
          ;
    call_procedure_statement: ID {             
                            $$ = new parse(0, "call_procedure_statement", "");
                            $$->children.push_back($1);
                            last = $$;
                            }
                            | ID LPAR expression_list RPAR {             
                            $$ = new parse(0, "call_procedure_statement", "");
                            $$->children.push_back($1);
                            $$->children.push_back($2);
                            $$->children.push_back($3);
                            $$->children.push_back($4);
                            last = $$;
                            }|ID LPAR expression_list error {             
                            $$ = new parse(0, "call_procedure_statement", "");
							yyerror("There miss a right bracket", @3.last_line, @3.last_column+1);
							}
                            ;
    expression_list: expression_list COMMA expression {             
                   $$ = new parse(0, "expression_list", "");
                   $$->children.push_back($1);
                   $$->children.push_back($2);
                   $$->children.push_back($3);
                   last = $$;
                   }|expression_list error expression {//没逗号    
                   $$ = new parse(0, "expression_list", "");
				   yyerror("There miss a comma", @1.last_line, @1.last_column+1);
				   }
                   | expression {             
                   $$ = new parse(0, "expression_list", "");
                   $$->children.push_back($1);
                   last = $$;
                   }
                   ;
    expression: simple_expression RELOP simple_expression {             
              $$ = new parse(0, "expression", "");
              $$->children.push_back($1);
              $$->children.push_back($2);
              $$->children.push_back($3);
              last = $$;
              }
              | simple_expression {             
              $$ = new parse(0, "expression", "");
              $$->children.push_back($1);
              last = $$;
              }
              ;
    RELOP: EQUAL {             
         $$ = new parse(0, "RELOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | NEQUAL {             
         $$ = new parse(0, "RELOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | LESS {             
         $$ = new parse(0, "RELOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | LE {             
         $$ = new parse(0, "RELOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | GREATER {             
         $$ = new parse(0, "RELOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | GE {             
         $$ = new parse(0, "RELOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         ;
    simple_expression: term {             
                     $$ = new parse(0, "simple_expression", "");
                     $$->children.push_back($1);
                     last = $$;
                     }
                     | ADD term {             
                     $$ = new parse(0, "simple_expression", "");
                     $$->children.push_back($1);
                     $$->children.push_back($2);
                     last = $$;
                     }
                     | SUB term {             
                     $$ = new parse(0, "simple_expression", "");
                     $$->children.push_back($1);
                     $$->children.push_back($2);
                     last = $$;
                     }
                     | simple_expression ADDOP term {             
                     $$ = new parse(0, "simple_expression", "");
                     $$->children.push_back($1);
                     $$->children.push_back($2);
                     $$->children.push_back($3);
                     last = $$;
                     }
                     ;
    ADDOP: ADD {             
         $$ = new parse(0, "ADDOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | SUB {             
         $$ = new parse(0, "ADDOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | OR {             
         $$ = new parse(0, "ADDOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         ;
    term: term MULOP factor {             
        $$ = new parse(0, "term", "");
        $$->children.push_back($1);
        $$->children.push_back($2);
        $$->children.push_back($3);
        last = $$;
        }
        | factor {             
        $$ = new parse(0, "term", "");
        $$->children.push_back($1);
        last = $$;
        }
        ;
    MULOP: MUL {             
         $$ = new parse(0, "MULOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | DIVISION {             
         $$ = new parse(0, "MULOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | DIV {             
         $$ = new parse(0, "MULOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | MOD {             
         $$ = new parse(0, "MULOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         | AND {             
         $$ = new parse(0, "MULOP", "");
         $$->children.push_back($1);
         last = $$;
         }
         ;
    factor: unsign_const_variable {             
          $$ = new parse(0, "factor", "");
          $$->children.push_back($1);
          last = $$;
          }
          | variable {             
          $$ = new parse(0, "factor", "");
          $$->children.push_back($1);
          last = $$;
          }
          | ID LPAR expression_list RPAR {             
          $$ = new parse(0, "factor", "");
          $$->children.push_back($1);
          $$->children.push_back($2);
          $$->children.push_back($3);
          $$->children.push_back($4);
          last = $$;
          }
          | LPAR expression RPAR {             
          $$ = new parse(0, "factor", "");
          $$->children.push_back($1);
          $$->children.push_back($2);
          $$->children.push_back($3);
          last = $$;
          }//|LPAR expression_list error {  //没有右括号           
//          $$ = new parse(0, "factor", "");
//		  yyerror("There miss a right bracket", @2.last_line, @2.last_column+1);
//		  }
          | NOT factor {             
          $$ = new parse(0, "factor", "");
          $$->children.push_back($1);
          $$->children.push_back($2);
          last = $$;
          }
          ;
    unsign_const_variable: NUM {             
                         $$ = new parse(0, "unsign_const_variable", "");
                         $$->children.push_back($1);
                         last = $$;
                         }
                         | SSCH {
                         $$ = new parse(0, "unsign_const_variable", "");
                         $$->children.push_back($1);
                         last = $$;
                         }
						 | MMCH {
						 $$ = new parse(0, "unsign_const_variable", "");
                         $$->children.push_back($1);
                         last = $$;
						 }
                         ;//不能有ID
%%
//
const char* output = "./pretreatment.pas";
//预处理,将大写换成小写
void pretreatment(const char* input){
    char C;
    FILE* fin = fopen(input, "r");
    FILE* fout = fopen(output, "w+");
    bool is_SCH = false;
    while(fscanf(fin, "%c", &C) == 1){
        if(C == '\''){
            is_SCH = (! is_SCH);
        }
        if(!is_SCH){
            if(C >= 'A' && C <= 'Z'){
                C = C - 'A' + 'a';
            }
        }
        fprintf(fout, "%c", C);
    }
    fclose(fin);
    fclose(fout);
    return;
}
//对于错误直接报错
void yyerror(const char *str)
{
	string error;
	error = string(str);
	error += ", location: " + to_string(yylineno-1) + "." + to_string(yycolumn-yyleng);
	yacc_error.push_back(error);
    fprintf(stderr,"error:%s\n",error.c_str());
    system("pause");
}
void yyerror(const char *str, YYLTYPE *loc)
{//处理单个字符的错误
	string error;
	error = "syntax error, " + string(str);
    error += ", location: " + to_string(loc->first_line);
    error += "." + to_string(loc->first_column);
    error += "-" + to_string(loc->last_line);
    error += "." + to_string(loc->last_column);
	yacc_error.push_back(error);
}
void yyerror(const char *str, int line, int col)
{//处理一行以内的错误
    string error;
	error = "syntax error, " + string(str);
    error += ", location: " + to_string(line);
    error += "." + to_string(col);
	yacc_error.push_back(error);
}
void yyerror(const char *str, int startLine, int startCol, int endLine, int endCol)
{//处理涉及多行的错误
    string error;
	error = "syntax error, " + string(str);
    error += ", location: " + to_string(startLine);
    error += "." + to_string(startCol);
    error += "-" + to_string(endLine);
    error += "." + to_string(endCol);
	yacc_error.push_back(error);
}

void yacc_error_print()
{
    for(auto it = yacc_error.begin(); it != yacc_error.end(); it++){
        cout << (*it) << endl;
    }
}

int yywrap(){
    return 1;
}

parse* syntax_process(const char* file_path)
{
    pretreatment(file_path);
    FILE* fp = fopen(output, "r");
    if(fp == NULL){
        printf("error");
        return NULL;
    }
    yyin = fp;
    yyparse();
    fclose(fp);
    remove(output);
    if(root != nullptr){
       // root->bfs();
        return root;
    }
    else if(last != nullptr){
        last->bfs();
        yacc_error_print();
        return NULL;
    }
    else{
        lex_error_print();
        return NULL;
    }
}
